/******************************************************************************/
#define MAX_CHAT_LENGTH 1024

#define CLIENT_SERVER_VERSION 0 // version of the client-server protocol used to determine that client and server exchange messages that they both can understand
/******************************************************************************/
enum CLIENT_SERVER_COMMAND // usually the first byte of data sent between client and server, format of the data that follows the command depends if it comes from server or client !
{
   CS_VERSION_CHECK , // check versions, must be as first command, performs a check if server and client use the same protocol version
   CS_INIT_CONN     , // initialize client/server connection, exchange basic information
   CS_TIME_TEST     , // time verification test, to avoid speedhacks, every once in a while client must test his time with the server, if server will detect too big time difference then player will get disconnected
   CS_DEBUG         , // send a debug message to the server
   CS_REGISTER      , // create      account
   CS_LOGIN         , // login  to   account
   CS_LOGOUT        , // logout from account
   CS_LIST_CHRS     , // list   characters in active account
   CS_CREATE_CHR    , // create character  in active account
   CS_DELETE_CHR    , // delete character  in active account
   CS_ENTER_GAME    , // enter game using selected character from active account
   CS_LEAVE_GAME    , // leave game
   CS_CHR_DISCONNECT, // remove character from nearby character list (neighbors), this is received when the character becomes too far away, changes world or logs out
   CS_CHR_CONNECT   , // insert character to   nearby character list (neighbors), this is received when the character becomes closer to us
   CS_CHR_VISUALS   , // character visuals exchanged only its visuals have changed, generally this is sent infrequently
   CS_CHR_POS       , // character position and basic animations (exchanged few times per second, generally this is sent frequently, keep data size as low as possible)
   CS_CHR_ANIM      , // character custom animation start
   CS_CHR_INV_SLOTS , // character inventory slots update
   CS_CHAT          , // send text message to all neighbors
   CS_BYE           , // disconnect
};
enum LOGIN_RESULT
{
   LOGIN_INVALID_USER_NAME         ,
   LOGIN_INVALID_PASSWORD          ,
   LOGIN_USER_DOES_NOT_EXIST       ,
   LOGIN_USER_OK_INCORRECT_PASSWORD,
   LOGIN_USER_ALREADY_LOGGED       ,
   LOGIN_USER_OK_PASSWORD_OK       ,
};
enum CHR_CREATE_RESULT
{
   CHR_CREATE_NOT_LOGGED_IN,
   CHR_CREATE_NO_ROOM      ,
   CHR_CREATE_INVALID_DATA ,
   CHR_CREATE_NAME_TAKEN   ,
   CHR_CREATE_OK           ,
};
/******************************************************************************/
struct DataLibrary // collection of string libraries for common exchanged file names (skeletons, animations, meshes, objects, ..) allows exchanging data file names with only few bytes instead of full strings, this is created by the server on its startup, and sent to each client when they connect
{
   StrLibrary skel, anim, mesh, obj;

   // io
   void save(File &f); // save Data Library to   file
   Bool load(File &f); // load Data Library from file, false on fail
}extern
   DL;
extern File DLFile;
/******************************************************************************/
struct Traffic // network traffic stats
{
   Flt last_time, send_speed, receive_speed;
   I64 last_sent, last_received;

   void update(I64 sent, I64 received);

   Traffic();
};
/******************************************************************************/
Bool ValidName    (Str name    ); // if 'name'     is a valid name for account or character
Bool ValidPassword(Str password); // if 'password' is a valid text for password
/******************************************************************************/
// Network commands
void ClientSendVersion(Connection &conn);
Bool ServerRecvVersion(File       &f   );
void ServerSendVersion(Connection &conn, Bool ok);
Bool ClientRecvVersion(File       &f   );

void ClientSendInitConnection(Connection &conn);
void ServerRecvInitConnection(File       &f   , Flt &time_difference, DateTime &client_utc);
void ServerSendInitConnection(Connection &conn);
Bool ClientRecvInitConnection(Connection &conn, DateTime &server_utc);

void ClientSendRegister(Connection &conn, C Str &name, C Str &password, C Str &email);
void ServerRecvRegister(File       &f   ,   Str &name,   Str &password,   Str &email);
void ServerSendRegister(Connection &conn, Bool  ok);
void ClientRecvRegister(File       &f   , Bool &ok);

void ClientSendLogin(Connection &conn, C Str &name, C Str &password);
void ServerRecvLogin(File       &f   ,   Str &name,   Str &password);
void ServerSendLogin(Connection &conn, LOGIN_RESULT  result);
void ClientRecvLogin(File       &f   , LOGIN_RESULT &result);

void ClientLogout(Connection &conn);

void ClientSendBye(Connection &conn);

void ClientSendListChrsRequest(Connection &conn);
void ServerSendListChrs       (Connection &conn, Memc<NetChr> &chrs);
void ClientRecvListChrs       (File       &f   , Memc<NetChr> &chrs);

void ClientSendCreateChr(Connection &conn, ChrCreateRequest &ccr);
void ServerRecvCreateChr(File       &f   , ChrCreateRequest &ccr);
void ServerSendCreateChr(Connection &conn, CHR_CREATE_RESULT  result);
void ClientRecvCreateChr(File       &f   , CHR_CREATE_RESULT &result);

void ClientSendDeleteChr(Connection &conn, C Str &chr_name, C Str &account_password);
void ServerRecvDeleteChr(File       &f   ,   Str &chr_name,   Str &account_password);

void ClientSendEnterGame(Connection &conn, C Str &chr_name);
void ServerRecvEnterGame(File       &f   ,   Str &chr_name);
void ServerSendEnterGame(Connection &conn, Bool  ok, NetChr &chr);
void ClientRecvEnterGame(File       &f   , Bool &ok, NetChr &chr);

void ClientLeaveGame(Connection &conn);

void ServerSendChrDisconnect(Connection &conn, C SockAddr &addr);
void ClientRecvChrDisconnect(File       &f   ,   SockAddr &addr);

struct ChrInfo
{
   SockAddr addr;
   Str      name;
   Flt      scale;
   MeshPtr  mesh;

   void save(File &f) {addr.save(f); f.putStr(name); f<<scale;      DL.mesh.putStr(f, mesh.name());}
   void load(File &f) {addr.load(f); f.getStr(name); f>>scale; mesh=DL.mesh.getStr(f);}
};
void ServerSendChrConnect(Connection &conn, ChrInfo &ci);
void ClientRecvChrConnect(File       &f   , ChrInfo &ci);

struct ChrVisuals
{
   SockAddr     addr;
   NetInventory inv ;

   void save(File &f)
   {
      f.putByte(CS_CHR_VISUALS);
      addr.save(f);
      inv.compress(f, true);
   }
   void load(File &f)
   {
      addr.load(f);
      inv.decompress(f);
   }
};
void ServerWriteChrVisuals(File       &f   , ChrVisuals &cv);
void ServerSendChrVisuals (Connection &conn, ChrVisuals &cv);
void ClientRecvChrVisuals (File       &f   , ChrVisuals &cv);

struct ChrPos
{
   SockAddr addr;
   Vec      pos;
   Flt      angle, stop_move, walk_run;

   void save(File &f, Bool include_addr)
   {
      f.putByte(CS_CHR_POS);
      if(include_addr)addr.save(f);
      f.cmpFlt3cm(pos.x).cmpFlt3cm(pos.y).cmpFlt3cm(pos.z).cmpAngle1(angle).cmpSatFlt1(stop_move).cmpSatFlt1(walk_run);
   }
   void load(File &f, Bool include_addr)
   {
      if(include_addr)addr.load(f);
      f.decFlt3cm(pos.x).decFlt3cm(pos.y).decFlt3cm(pos.z).decAngle1(angle).decSatFlt1(stop_move).decSatFlt1(walk_run);
   }
};
void ClientSendChrPos (Connection &conn, ChrPos &cp);
void ServerRecvChrPos (Connection &conn, ChrPos &cp);
void ServerWriteChrPos(File       &f   , ChrPos &cp);
void ServerSendChrPos (Connection &conn, ChrPos &cp);
void ClientRecvChrPos (File       &f   , ChrPos &cp);

void ClientSendChrAnim (Connection &conn, C Str &anim);
void ServerRecvChrAnim (File       &f   ,   Str &anim);
void ServerWriteChrAnim(File       &f   , C SockAddr &addr, C Str &anim);
void ClientRecvChrAnim (File       &f   ,   SockAddr &addr,   Str &anim);

void ClientSendChrInvSlots(Connection &conn, Int (&slots)[SLOT_NUM]);
void ServerRecvChrInvSlots(File       &f   , Int (&slots)[SLOT_NUM]);

void ClientSendTimeTest(Connection &conn);
void ServerRecvTimeTest(File       &f   , Flt &cur_time);

void ClientSendDebug(Connection &conn, C Str &message);
void ServerRecvDebug(File       &f   ,   Str &message);

void ClientSendChat (Connection &conn, C Str &text);
void ServerRecvChat (File       &f   ,   Str &text);
void ServerWriteChat(File       &f   , C SockAddr &addr, C Str &text);
void ClientRecvChat (File       &f   ,   SockAddr &addr,   Str &text);
/******************************************************************************/
